<?php
declare (strict_types=1);

namespace app\command;

use app\common\business\DiseasePath;
use app\common\lib\Redis;
use app\common\lib\ZhyxBeanstalkd;
use app\common\lib\ZhyxMongo;
use app\common\model\BaseModel;
use app\common\model\CollectCase;
use app\common\model\CollectClass;
use app\common\model\DiseasePatientTaskDetail;
use app\common\model\PacketConfig;
use app\common\model\PatientRecord;
use app\common\model\TimingTask;
use app\impl\SimpleFactory;
use Pheanstalk\Exception\ClientException;
use Pheanstalk\Exception\ConnectionException;
use Pheanstalk\Exception\ServerException;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\Exception;
use think\facade\Log;

class AutoCollect extends Command
{
    private array $groupList;
    private string $packetId;

    protected function configure(): void
    {
        // 指令配置
        $this->setName('autoCollect')
            ->setDescription('患者自动收案');
    }

    /**
     * @throws \Exception
     */
    protected function execute(Input $input, Output $output)
    {

        //获取孕周分组
        $groupList = $this->getGroupList();

        //获取疾病分组
        $diseaseList = $this->getDiseaseList();
        //获取当日数据
        $sourceData = $this->getSourceData();
        foreach ($sourceData as $k => $v) {

            $output->writeln("开始同步" . $v["name"] . "患者自动入组数据");
            //生成周任务
            $this->generateTaskByWeek($v, $groupList[$v["dept_id"]] ?? []);
            //生成疾病任务
            $this->generateTaskByDisease($v, $diseaseList[$v["dept_id"]] ?? []);
            (new PatientRecord())->where([["id", "=", $v["rid"]]])->save(["is_sync" => true]);
            //判断是否有流产，如果有需要停路径
            /*$killRulesDiagnose = ["流产"];
            if ($this->containsTarget($v["diagnosis"], $killRulesDiagnose)) {
                $this->killRulePath($v["patientId"]);
            }*/
        }
        $output->writeln("同步成功");

    }

    /**
     * 根据疾病生成自动入组任务
     * @param $data
     * @param $diseaseGroupList
     * @throws \Exception
     */
    private function generateTaskByDisease($data, $diseaseGroupList): void
    {

        $groupTask = [];
        if (!empty($diseaseGroupList)) {
            $data['packet_id'] = $diseaseGroupList[0]["packet_id"];

            $initData = [
                'task_name' => '自动入组',
                'task_status' => 0,
                'deleted_at' => 0,
                'type' => 'join_group',
                'task_plan_date' => date("Y-m-d"),
            ];
            foreach ($diseaseGroupList as $k => $v) {

                if ($this->containsTarget($data["diagnosis"], $v["releases"])) {
                    $groupTask[] = array_merge($initData, ["group_id" => $v["group_id"], "group_name" => $v["className"], 'task_data' => [
                        'group_id' => $v["group_id"],
                        'patient_id' => $data["patientId"]
                    ]]);
                }

            }
            //存在孕周，需要将此患者进行收案操作
            if (!empty($groupTask) && $this->putTheCaseAway((array)$data, 1)) {
                (new TimingTask())->saveAll($groupTask);
            }
        }
    }


    /**
     * 生成孕周计划任务
     * @param $data
     * @throws \Exception
     */
    private function generateTaskByWeek($data, $groupList): void
    {
        $weekHasGroup = [];

        if (!empty($groupList)) {
            $data['packet_id'] = $groupList[0]["packet_id"];
            $weekDeptIdArr = [69, 67];
            //判断是否是产科门诊

            if (in_array($data["dept_id"], $weekDeptIdArr, true)) {

                $diagnosis = $data["diagnosis"];
                $week = $this->extractPregnancyWeek($diagnosis);

                if ($week > 0) {

                    $weekHasGroup = $this->getGroupByWeek($data, $week, $groupList);
                    //存在孕周，需要将此患者进行收案操作
                    if (!empty($weekHasGroup) && $this->putTheCaseAway((array)$data)) {
                        (new TimingTask())->saveAll($weekHasGroup);
                    }
                }
            }
        }
    }

    /**
     * 患者收案
     * @param $data
     */
    private function putTheCaseAway($data, $type = 0)
    {

        //判断pid是否存在
        if ($data["pid"] == "") {
            return false;
        }
        $isExists = (new CollectCase())->where([["pid", "=", $data["pid"]], ["dept_id", "=", (int)$data["dept_id"]]])->find();
        if (empty($isExists)) {
            $data["updated_at"] = $data["created_at"] = time();
            $data["type"] = 'auto';
            //执行自动绑定随访路径
            $data["doctors"][0] = [
                'attendingDoctorId' => $data['attendingDoctorId'],
                'attendingDoctorNo' => $data['attendingDoctorNo'],
                'attendingDoctorName' => $data['attendingDoctorName'],
            ];
            $rst = (new CollectCase())->insert($data);
            if ($rst && $type === 0) {
                return $this->bindRules($data);
            }

        } else {

            $doctors = $isExists["doctors"];
            $doctors[] = [
                'attendingDoctorId' => $data['attendingDoctorId'],
                'attendingDoctorNo' => $data['attendingDoctorNo'],
                'attendingDoctorName' => $data['attendingDoctorName'],
            ];
            $isExists->save([
                'attendingDoctorId' => $data['attendingDoctorId'],
                'attendingDoctorNo' => $data['attendingDoctorNo'],
                'attendingDoctorName' => $data['attendingDoctorName'],
                'doctors' => $doctors
            ]);
        }
        return $type;
    }


    /**
     * 根据周数计算分组
     * @param $data
     * @param $week
     * @param $groupList
     * @return array
     */
    private function getGroupByWeek($data, $week, $groupList): array
    {

        $isNormal = false;
        $groupTask = [];
        $initData = [
            'task_name' => '自动入组',
            'task_status' => 0,
            'deleted_at' => 0,
            'type' => 'join_group',
        ];

        foreach ($groupList as $k => $v) {
            if ($isNormal) {
                //获取到下一个分组的周数
                $nextWeekStart = $v["start_value"];
                //计算当前孕期差值
                $diffWeek = $nextWeekStart - $week;
                if ($diffWeek > 0) {
                    $taskPlanDate = date("Y-m-d", strtotime("+" . $diffWeek . " week"));
                    $groupTask[] = array_merge($initData, ["group_id" => $v["group_id"], 'task_data' => [
                        'group_id' => $v["group_id"],
                        'patient_id' => $data["patientId"],
                        'patient_uuid' => $data["pid"],
                        'patient_name' => $data['name'],
                        'sex' => $data['sex']
                    ], 'task_plan_date' => $taskPlanDate, 'group_name' => $v['className']]);
                }
            } else {
                if ($v["start_value"] <= $week && $v["end_value"] > $week) {

                    //直接匹配到，直接设置成今天就推送
                    $groupTask[] = array_merge($initData, ["group_id" => $v["group_id"], 'task_data' => [
                        'group_id' => $v["group_id"],
                        'patient_id' => $data["patientId"],
                        'patient_uuid' => $data["pid"],
                        'patient_name' => $data['name'],
                        'sex' => $data['sex']
                    ], 'task_plan_date' => (string)date("Y-m-d"), 'group_name' => $v['className']]);
                    $isNormal = true;
                }
            }

        }

        return $groupTask;

    }


    /**
     * 提取孕周
     * @param string $diagnosis
     * @return int|mixed
     */
    private function extractPregnancyWeek(string $diagnosis)
    {

        if (mb_strpos($diagnosis, "孕") === 0) {
            $pattern = '/孕.*?(\d+)周/';
            if (preg_match($pattern, $diagnosis, $matches)) {
                return $matches[1];
            }
        }
        return 0;
    }

    /**
     * 获取数据源
     * @return array
     */
    private function getSourceData(): array
    {
        $date = date('Y-m-d');
        $date = '2024-10-29';
        $createdAt = time();
        $collection = ZhyxMongo::getInstance()->setCollection('patient_record');
        $cursor = $collection->aggregate([['$match' => ['visitTime' => ['$eq' => $date], 'is_sync' => ['$exists' => false], 'diseaseName' => ['$ne' => null], 'type' => 1]], ['$sort' => ['visitTime' => 1]], ['$group' => ['_id' => '$patientId', 'rid' => ['$first' => ['$toString' => '$_id']], 'sex' => ['$first' => '$patientSex'], 'name' => ['$first' => '$patientName'], 'patientId' => ['$last' => '$patientId'], 'patientIdNo' => ['$first' => '$patientIdNo'], 'diagnosis' => ['$last' => '$diseaseName'], 'diseaseCode' => ['$last' => '$diseaseCode'], 'dept_id' => ['$last' => '$deptId'], 'dept_name' => ['$last' => '$deptName'], 'attendingDoctorId' => ['$last' => '$attendingDoctorId'], 'attendingDoctorNo' => ['$last' => '$attendingDoctorNo'], 'attendingDoctorName' => ['$last' => '$attendingDoctorName']]], ['$lookup' => ['from' => 'patient_info', 'localField' => '_id', 'foreignField' => 'patientId', 'as' => 'results']], ['$addFields' => ['creator_id' => 0, 'deleted_at' => 0, 'created_at' => $createdAt, 'updated_at' => $createdAt, 'pid' => ['$toString' => ['$arrayElemAt' => ['$results._id', 0]]]]], ['$project' => ['_id' => false, 'results' => false]]]);

        //$cursor = $collection->aggregate([['$match' => ['diseaseName' => ['$ne' => null], 'type' => 1, 'patientId' => ['$in' => ["578350", "349426"]]]], ['$sort' => ['visitTime' => 1]], ['$group' => ['_id' => '$patientId', 'sex' => ['$first' => '$patientSex'], 'name' => ['$first' => '$patientName'], 'patientId' => ['$last' => '$patientId'], 'patientIdNo' => ['$first' => '$patientIdNo'], 'diagnosis' => ['$last' => '$diseaseName'], 'diseaseCode' => ['$last' => '$diseaseCode'], 'dept_id' => ['$first' => '$deptId'], 'dept_name' => ['$last' => '$deptName']]], ['$lookup' => ['from' => 'patient_info', 'localField' => '_id', 'foreignField' => 'patient_id', 'as' => 'results']], ['$addFields' => ['creator_id' => 0, 'deleted_at' => 0, 'created_at' => 1727075037, 'updated_at' => 1727075037, 'pid' => ['$toString' => ['$arrayElemAt' => ['$results._id', 0]]]]], ['$project' => ['_id' => false, 'results' => false]]]);
        return iterator_to_array($cursor);

    }

    /**
     * 获取分组重新合并成一个新的数组结构 下表key是部门id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function getGroupList(): array
    {
        //获取所有的分组
        $groupArr = [];
        $groupName = (new CollectClass())->where([["platform", "=", 0]])->field(["className", "department_id", "mapping_value", "packet_id"])->order('sort', 'asc')->select();
        if (!empty($groupName)) {

            foreach ($groupName as $k => $v) {
                $groupArr[$v["department_id"]][] = [
                    'className' => $v['className'],
                    'start_value' => $v["mapping_value"][0],
                    'end_value' => $v["mapping_value"][1] ?? $v["mapping_value"][0],
                    'group_id' => $v["id"],
                    'packet_id' => $v["packet_id"]
                ];
            }
        }
        return $groupArr;
    }

    private function getDiseaseList(): array
    {
        //获取所有的分组
        $diseaseArr = [];
        $diseaseList = (new CollectClass())->where([["platform", "=", 1]])->field(["className", "department_id", "mapping_value", "packet_id"])->select();

        if (!empty($diseaseList)) {
            foreach ($diseaseList as $k => $v) {
                $diseaseArr[$v["department_id"]][] = [
                    'className' => $v['className'],
                    "releases" => $v["mapping_value"],
                    "group_id" => $v["id"],
                    "packet_id" => $v["packet_id"]
                ];
            }
        }
        return $diseaseArr;
    }

    private function containsTarget($string, $targets): bool
    {

        // 将目标字符串数组转换为正则表达式
        $pattern = '/' . implode('|', array_map('preg_quote', $targets)) . '/i';

        // 使用 preg_match 检查字符串是否匹配
        return preg_match($pattern, $string) === 1;
    }

    /**
     * 绑定随访路径
     */
    private function bindRules(array $data): bool
    {

        //根据packet_id获取随访路径信息
        try {
            $packetConfig = (new PacketConfig())->field(["follow_path", "follow_doctors"])->find($data["packet_id"]);
            if (!empty($packetConfig["follow_path"])) {
                $queryBody = [];
                foreach ($packetConfig["follow_path"] as $k => $v) {
                    $queryBody["disease_path"][] = [
                        'disease_path_id' => $v['path_id'],
                        'disease_path_name' => $v['path_name']
                    ];
                }
                $queryBody["doctors"] = $packetConfig["follow_doctors"] ?? [];

                $taskData = [
                    'patientId' => $data['patientId'],
                    'doctors' => $queryBody["doctors"],
                    'disease_path' => $queryBody['disease_path'],
                    'creator_name' => '系统自动推送',
                    'creator_id' => 0,
                    'tubeName' => 'SendDiseasePathPlan'
                ];
                $deliveryTask = ZhyxBeanstalkd::getInstance()->beansTalk->useTube("sendDiseasePathPlan")->put(json_encode($taskData, JSON_THROW_ON_ERROR), 0, 0);
                return true;
            }
        } catch (\Exception $exception) {
            Log::error("随访路径绑定失败:" . $exception->getMessage());
            return false;
        }
        return true;
    }

    private function killRulePath(string $patientId): void
    {
        //判断当前患者是否绑定随访孕周任务
        (new DiseasePatientTaskDetail())->where([["patient_id", "=", $patientId], ['latest_status', "=", 0]])->update([
            'latest_status' => 4
        ]);


    }

}